package com.kexilo.core.common.filter;

import com.kexilo.core.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.util.regex.Pattern;

/**
 * XSS过滤器
 * 
 * @author Kexilo
 */
public class XssFilter implements Filter {
    
    private static final Logger log = LoggerFactory.getLogger(XssFilter.class);
    
    /**
     * XSS脚本模式
     */
    private static final Pattern[] XSS_PATTERNS = {
        Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),
        Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
        Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
        Pattern.compile("</script>", Pattern.CASE_INSENSITIVE),
        Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
        Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
        Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
        Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE),
        Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE),
        Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)
    };
    
    @Override
    public void init(FilterConfig filterConfig) {
        log.info("XSS过滤器初始化完成");
    }
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        XssHttpServletRequestWrapper wrappedRequest = new XssHttpServletRequestWrapper(httpRequest);
        
        chain.doFilter(wrappedRequest, response);
    }
    
    @Override
    public void destroy() {
        log.info("XSS过滤器销毁");
    }
    
    /**
     * XSS请求包装器
     */
    private static class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
        
        public XssHttpServletRequestWrapper(HttpServletRequest request) {
            super(request);
        }
        
        @Override
        public String[] getParameterValues(String parameter) {
            String[] values = super.getParameterValues(parameter);
            if (values == null) {
                return null;
            }
            
            int count = values.length;
            String[] encodedValues = new String[count];
            for (int i = 0; i < count; i++) {
                encodedValues[i] = stripXss(values[i]);
            }
            
            return encodedValues;
        }
        
        @Override
        public String getParameter(String parameter) {
            String value = super.getParameter(parameter);
            return stripXss(value);
        }
        
        @Override
        public String getHeader(String name) {
            String value = super.getHeader(name);
            return stripXss(value);
        }
        
        /**
         * 移除XSS攻击脚本
         */
        private String stripXss(String value) {
            if (StringUtils.isNotEmpty(value)) {
                // 移除可能的XSS脚本
                for (Pattern pattern : XSS_PATTERNS) {
                    value = pattern.matcher(value).replaceAll("");
                }
                
                // HTML实体编码
                value = value.replaceAll("<", "&lt;")
                           .replaceAll(">", "&gt;")
                           .replaceAll("\\(", "&#40;")
                           .replaceAll("\\)", "&#41;")
                           .replaceAll("'", "&#39;")
                           .replaceAll("\"", "&quot;");
            }
            return value;
        }
    }
}
